package org.afk.sisy.gui.swing;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.List;

import javax.swing.*;
import javax.swing.border.*;

import net.miginfocom.swing.*;

import org.afk.sisy.*;
import org.afk.sisy.db.*;
import org.afk.tools.log.*;

public class SisyGuiApp
{

	private final PreferencesWrapper preferences;
	private final HashMap<String, Component> components = new HashMap<String, Component>();

	private final JFrame mainFrame = new JFrame();
	private final JLabel status = new JLabel("Started " + new Date());
	private final ErrorHandler errorHandler;
	private final JPanel buttonPanel = new JPanel();
	private final JButton newJobButton = new JButton("Create Job");
	private final JButton deleteJobButton = new JButton("Delete Job");
	private final JButton runJobButton = new JButton("Run active Jobs");
	private final JPanel jobPanel = new JPanel();
	private final Icons icons = new Icons();

	private final JobDataBase jobDb;

	private ImageIcon errorIcon;

	private Icon deleteIcon;

	private Icon runIcon;

	public SisyGuiApp(final PreferencesWrapper preferences, final JobDataBase jobDb)
	{
		this.preferences = preferences;
		this.errorHandler = new SwingErrorHandler(this.status);
		this.jobDb = jobDb;
		initMainFrame();
	}

	private void addJobs(final Container parent) throws SQLException
	{
		final List<SisyJob> jobs = this.jobDb.getJobs();
		for (final SisyJob sisyJob : jobs)
			parent.add(createSingleJobPanel(sisyJob));
	}

	private Component createDataBaseTextField(final Path dir)
	{
		final JTextField field = createTextField();
		if (dir != null)
			field.setText(dir.toString());
		return field;
	}

	private JComboBox<String> createHashSelection(final String hash)
	{
		final JComboBox<String> comp = new JComboBox<String>(new Vector<String>(Arrays.asList("SHA1", "off", "MD5")));
		if (hash != null)
			comp.setSelectedItem(hash);
		else
			comp.setSelectedItem("off");
		return comp;
	}

	private Component createSingleJobPanel(final SisyJob job)
	{
		final JPanel jobPanel = new JPanel();
		jobPanel.setLayout(new MigLayout());

		//		jobPanel.add(createActiveCheckBox(job.isClean()), "west");
		jobPanel.add(createDataBaseTextField(job.getDataBase()), "width 20%");

		jobPanel.add(new JLabel("Primary"));
		jobPanel.add(createSourceTextField(job.getPrimaryDir()), "width 20%");

		jobPanel.add(new JLabel("Secondary"));
		jobPanel.add(createTargetTextField(job.getSecondaryDir()), "width 20%");

		//		jobPanel.add(createCleanCheckBox(job.isClean()));
		//		jobPanel.add(createLowCheckBox(job.isLowBandwith()));

		jobPanel.add(new JLabel("Hash"));
		jobPanel.add(createHashSelection(job.getAlgorythm()), "east");

		jobPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		return jobPanel;

	}

	private Component createSourceTextField(final Path dir)
	{
		final JTextField field = createTextField();
		if (dir != null)
			field.setText(dir.toString());
		return field;
	}

	private Component createTargetTextField(final Path dir)
	{
		final JTextField field = createTextField();
		if (dir != null)
			field.setText(dir.toString());
		return field;
	}

	private JTextField createTextField()
	{
		final JTextField field = new JTextField();
		return field;
	}

	private void initButtonPanel(final Container parent, final String constraint)
	{
		parent.add(this.buttonPanel, constraint);

		initNewProjectButton(this.buttonPanel);
		initDeleteProjectButton(this.buttonPanel);
		initRunProjectButton(this.buttonPanel);

	}

	private void initDeleteProjectButton(final Container parent)
	{
		this.deleteJobButton.addActionListener(new DeleteProjectButtonActionListener(this));
		this.deleteJobButton.setEnabled(false);
		this.deleteJobButton.setIcon(this.deleteIcon);
		parent.add(this.deleteJobButton);
	}

	private void initJobPanel(final Container parent, final Object constraint)
	{
		final JScrollPane scroller = new JScrollPane(this.jobPanel);
		this.jobPanel.setLayout(new BoxLayout(this.jobPanel, BoxLayout.Y_AXIS));
		parent.add(scroller, constraint);

		try
		{
			addJobs(this.jobPanel);
		}
		catch (final SQLException e)
		{
			this.errorHandler.warning("While adding Jobs", e);
		}
	}

	private void initMainFrame()
	{
		this.mainFrame.setTitle("Sisy " + "Eva");
		this.mainFrame.setBounds(this.preferences.getMainFrameX(), this.preferences.getMainFrameY(), this.preferences.getMainFrameWidth(),
				this.preferences.getMainFrameHeight());
		this.mainFrame.setExtendedState(this.preferences.getMainFrameExtendedState());
		this.mainFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		this.mainFrame.setIconImage(this.icons.getFrameIcon().getImage());
		this.mainFrame.setLayout(new MigLayout());
		this.mainFrame.addWindowListener(new WindowAdapter()
		{
			@Override
			public void windowClosing(final WindowEvent e)
			{
				save();
				System.exit(0);
			}
		});

		initStatusMessage(this.mainFrame, "dock south");
		initJobPanel(this.mainFrame, "dock center, grow");
		initButtonPanel(this.mainFrame, "dock north");
	}

	private void initNewProjectButton(final Container parent)
	{
		this.newJobButton.addActionListener(new NewProjectButtonActionListener(this, preferences));
		this.newJobButton.setIcon(this.icons.getAddIcon());
		parent.add(this.newJobButton);
	}

	private void initRunProjectButton(final Container parent)
	{
		this.runJobButton.addActionListener(new RunProjectButtonActionListener(this));
		this.runJobButton.setEnabled(false);
		this.runJobButton.setIcon(this.runIcon);
		parent.add(this.runJobButton);
	}

	private void initStatusMessage(final JFrame parent, final Object constraint)
	{
		this.status.setBackground(Color.RED);
		this.status.setOpaque(false);
		this.status.addMouseListener(new MouseListener()
		{

			@Override
			public void mouseClicked(final MouseEvent e)
			{
				if (SisyGuiApp.this.errorHandler instanceof SwingErrorHandler)
					if (((SwingErrorHandler) SisyGuiApp.this.errorHandler).getLastError() != null)
					{
						final ByteArrayOutputStream out = new ByteArrayOutputStream();
						final PrintStream stringWriter = new PrintStream(out);
						((SwingErrorHandler) SisyGuiApp.this.errorHandler).getLastError().printStackTrace(stringWriter);
						JOptionPane.showMessageDialog(SisyGuiApp.this.mainFrame, new String(out.toByteArray()), "Last error:", JOptionPane.WARNING_MESSAGE,
								SisyGuiApp.this.errorIcon);
					}

			}

			@Override
			public void mouseEntered(final MouseEvent e)
			{}

			@Override
			public void mouseExited(final MouseEvent e)
			{}

			@Override
			public void mousePressed(final MouseEvent e)
			{}

			@Override
			public void mouseReleased(final MouseEvent e)
			{}
		});

		parent.add(this.status, constraint);

	}

	private void save()
	{
		this.preferences.setMainFrameX(this.mainFrame.getX());
		this.preferences.setMainFrameY(this.mainFrame.getY());
		this.preferences.setMainFrameWidth(this.mainFrame.getWidth());
		this.preferences.setMainFrameHeight(this.mainFrame.getHeight());
		this.preferences.setMainFrameExtendedState(this.mainFrame.getExtendedState());
	}

	public boolean containsKey(final Object key)
	{
		return this.components.containsKey(key);
	}

	public Component get(final Object key)
	{
		return this.components.get(key);
	}

	public JButton getDeleteJobButton()
	{
		return this.deleteJobButton;
	}

	public Icons getIcons()
	{
		return this.icons;
	}

	public JFrame getMainFrame()
	{
		return this.mainFrame;
	}

	public JButton getNewJobButton()
	{
		return this.newJobButton;
	}

	public JPanel getProjectPanel()
	{
		return this.buttonPanel;
	}

	public JLabel getStatus()
	{
		return this.status;
	}

	public void newJob(final SisyJob sisyJob)
	{
		try
		{
			this.jobDb.addJob(sisyJob);
			this.jobPanel.add(createSingleJobPanel(sisyJob));
		}
		catch (final SQLException e)
		{
			this.errorHandler.warning("While adding job", e);
		}
	}

	public void newJobCreated(final SisyJob job)
	{
		// TODO Auto-generated method stub

	}

	public Component put(final String key, final Component value)
	{
		return this.components.put(key, value);
	}

	public void show()
	{
		this.mainFrame.setVisible(true);
	}

}
